//
//  SecondViewController.m
//  tableViewLazyDemo
//
//  Created by kingboyrang on 2021/11/20.
//  Copyright © 2021 wulanzhou. All rights reserved.
//

#import "SecondViewController.h"
#import "ImageCell.h"

#define cellIdentifierID @"ImageCell"

// 定义一个block
typedef void(^RunloopBlock)(void);

@interface SecondViewController ()<UITableViewDataSource,UITableViewDelegate>{
    CFRunLoopObserverRef _defaulModeObserver;
}
@property (nonatomic,strong) UITableView *tableView;

/// 定时器
@property (nonatomic, strong) NSTimer *timer;
/// 任务队列
@property (nonatomic, strong) NSMutableArray *tasks;
/// 最大任务数
@property (nonatomic, assign) NSUInteger maxQueueLength;

@property (assign, nonatomic) BOOL display;

@end


#pragma mark - runloop 观察者回调
static void Callback(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info) {
    SecondViewController *vc = (__bridge SecondViewController *)info;
    //无任务  退出
    if (vc.tasks.count == 0) {
        return;
    }
    
   
    
    if (vc.display) {
        //从数组中取出任务
        RunloopBlock task = vc.tasks.firstObject;
        if (task) {
            task();
            //执行完任务之后移除任务
            [vc.tasks removeObjectAtIndex:0];
        }
    }
    
}

@implementation SecondViewController

- (void)timerMethod {
    // 添加timer才开启block任务的执行，不然数组tasks会因为添加30个而导致数组中保存的仅仅是最后五个，TableView一出来cell图片没显示，因为就没有对应的任务
       self.display = YES;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    
    /****
     
       实现原理: RunLoop循环只渲染一张图片
       
       通过定时器保持runloop长存，每次RunLoop在即将进入休眠的时候就会通知observer，observer就会调用创建时传入的回调函数。
       如果数组中没有待执行的代码块则直接返回；如果有就取出第一条代码块执行，并从数组中移除。这样可以保证每次RunLoop循环只渲染一张图片。
       
       */
    
    //添加table
    self.tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain];
    self.tableView.delegate = self;
    self.tableView.dataSource = self;
    [self.tableView registerClass:[ImageCell class] forCellReuseIdentifier:cellIdentifierID];
    [self.view addSubview:self.tableView];
    
    
    // 创建观察者
   // 拿到当前的runloop
   CFRunLoopRef runloop = CFRunLoopGetCurrent();
   // 定义一个上下文
   CFRunLoopObserverContext context = {0, (__bridge void *)(self), NULL, NULL, NULL};
   // 创建一个观察者
   _defaulModeObserver  = CFRunLoopObserverCreate(NULL, kCFRunLoopBeforeWaiting, YES, 0, &Callback, &context);
   CFRunLoopAddObserver(runloop, _defaulModeObserver, kCFRunLoopCommonModes);
   CFRelease(runloop);
   
   self.maxQueueLength = 51;
   self.tasks = [NSMutableArray array];
   // 让runloop一直转起来
   self.timer = [NSTimer scheduledTimerWithTimeInterval:0.0001 target:self selector:@selector(timerMethod) userInfo:nil repeats:YES];
    
    
    // Do any additional setup after loading the view.
}

- (void)viewWillAppear:(BOOL)animated {
    // 添加观察者到runloop中
    if (_defaulModeObserver) {
        CFRunLoopAddObserver(CFRunLoopGetMain(), _defaulModeObserver, kCFRunLoopCommonModes);
    }
}

- (void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];
    
    if (_defaulModeObserver) {
        // 移除观察者
        CFRunLoopRemoveObserver(CFRunLoopGetMain(), _defaulModeObserver, kCFRunLoopCommonModes);
    }
}

- (void)viewDidDisappear:(BOOL)animated {
    [super viewDidDisappear:animated];
    
    /// 移除所有未执行的操作
    [self.tasks removeAllObjects];
    /// 暂停定时器
    [self.timer invalidate];
    self.timer = nil;
}

- (void)dealloc {
    if (_defaulModeObserver != NULL) {
        // 释放观察者
        CFRelease(_defaulModeObserver);
        _defaulModeObserver = NULL;
    }
    NSLog(@"%s", __func__);
}

#pragma mark - Table view data source

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return 1000;
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
    return 100.0f;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    ImageCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifierID forIndexPath:indexPath];
    NSInteger row = indexPath.row;
    cell.imageView1.image = nil;
    cell.imageView2.image = nil;
    cell.imageView3.image = nil;
    
    [self addTask:^{
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
             UIImage *img = [UIImage imageNamed:[NSString stringWithFormat:@"%ld",(long)(row%3)]];
             dispatch_async(dispatch_get_main_queue(), ^{
                cell.imageView1.image = img;
            });
        });
    }];
    
    [self addTask:^{
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
             UIImage *img = [UIImage imageNamed:[NSString stringWithFormat:@"%ld",(long)(row%3)]];
             dispatch_async(dispatch_get_main_queue(), ^{
                cell.imageView2.image = img;
            });
        });
    }];
    [self addTask:^{
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
             UIImage *img = [UIImage imageNamed:[NSString stringWithFormat:@"%ld",(long)(row%3)]];
             dispatch_async(dispatch_get_main_queue(), ^{
                cell.imageView3.image = img;
            });
        });
    }];
    
    // runloop
    /**
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        UIImage *img = [UIImage imageNamed:[NSString stringWithFormat:@"%ld",(long)(row%3)]];
       dispatch_async(dispatch_get_main_queue(), ^{
           [self addTask:^{
               cell.imageView1.image = img;
           }];
       });
    });
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
       UIImage *img = [UIImage imageNamed:[NSString stringWithFormat:@"%ld",(long)(row%3)]];
       dispatch_async(dispatch_get_main_queue(), ^{
           [self addTask:^{
               cell.imageView2.image = img;
           }];
       });
    });
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        UIImage *img = [UIImage imageNamed:[NSString stringWithFormat:@"%ld",(long)(row%3)]];
       dispatch_async(dispatch_get_main_queue(), ^{
           [self addTask:^{
               cell.imageView3.image = img;
           }];
       });
    });
     **/
    
    return cell;
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
    [tableView deselectRowAtIndexPath:indexPath animated:YES];
}

- (void)addTask:(RunloopBlock)task {
   

    if (self.display) {
        // 判断当前待执行的代码块是否超出最大代码块数
        if (self.tasks.count > self.maxQueueLength) {
            // 干掉最开始的代码块
            [self.tasks removeObjectAtIndex:0];
        }
    }
    // 将代码块添加到可变数组中
    [self.tasks addObject:task];
    
}

/*
#pragma mark - Navigation

// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    // Get the new view controller using [segue destinationViewController].
    // Pass the selected object to the new view controller.
}
*/

@end



